package com.sinosoft.brokerchannel.base.utile;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.Map;

/**   
  * 类描述:[从redis中获取数据]
  * @author [@user] wem
  * @date [2017年9月20日 上午11:12:18]
  * @version [v1.0]
  */
public abstract class BaseCacheWorker <P, R> {

	/** redis工具**/
	@Autowired
	private RedisUtils redisUtil;
	
	private final Logger logger = LoggerFactory.getLogger(this.getClass());
    /**
     * 	 
     *  需求名称：
     *  功能:[从redis中获取数据,如果redis中没有则去数据库中获取]
     *  @auther [@user]
     *  @date 2017年9月20日 下午3:24:24
     *  功能说明：
     *	   1.说明1；<br/>
     *	   2.说明2。<br/>
     *     ······
     *  @param key key
     *  @param clazz clazz
     *  return
     */
	@SuppressWarnings("unchecked")
	public R getDate(P key, Class<R> clazz) {
		// 配置keys
		String getkeys = getkeys(key,  clazz);
		this.logger.debug("生成keys = "+getkeys);
		//从redis中获取数据
		Object res = this.redisUtil.get(getkeys);
		// 如果redis中有数据 直接返回
		if(! ToolUtils.isNullOrEmpty(res)) {
			this.logger.debug("从redis中得到数据  ");
			return (R) res;
		}
		// 从MySQL中获取数据
		R queryDate = queryTableByKey(key); 
		if (!ToolUtils.isNullOrEmpty(queryDate)) {
			// 如果数据库中有数据 则要查询写入reds
			this.redisUtil.set(getkeys, queryDate);
			this.logger.debug("从MySQL中得到数据  ");
			return (R) queryDate;
		} 
		return null;
	}
    /**
     * 功能:[ 根据传入的方法名称，调用]<br/>
     * 创建时间 :[2017/11/29 13:12]<br/>
     * @author [wem]
     * @param key  查询条件，最终会作为redis中的key ,也是调用方法中的参数
     *              例如方法 methodName（Map<String,Object> key）
     * @param clazz 写 methodName方法的类
     * @param methodName  方法名称
     * @param mybatisDao  这个参数是Mybatis查询时用到的Dao
     * @return []
    */
	public  R  getDateToMethod(Map<String,Object> key,  String methodName,Class clazz,Object mybatisDao) {

		//配置keys
		String getkeys = getStringKeys(key,  clazz);
		this.logger.debug("生成keys = "+getkeys);
		//从redis中获取数据
		Object res = this.redisUtil.get(getkeys);
		// 如果redis中有数据 直接返回
		if(! ToolUtils.isNullOrEmpty(res)) {
			this.logger.debug("从redis中得到数据  ");
			return (R) res;
		}
		// 从MySQL中获取数据
        R queryDate = queryByMysql(clazz,methodName,mybatisDao, key);
		if (!ToolUtils.isNullOrEmpty(queryDate)) {
			// 如果数据库中有数据 则要查询写入reds
			this.redisUtil.set(getkeys, queryDate);
			this.logger.debug("从MySQL中得到数据  ");
			return (R) queryDate;
		}
		return null;
	}
	/**
	 * 功能:[ 反射从Mysql 中查询数据]<br/>
	 * 创建时间 :[2017/11/30 19:00]<br/>
	 * @author [wem]
	 * @param clazz 类型
	 * @param methodName 方法名
	 * @param mybatisDao mybatisDao
	 * @param methodParams 参数
	 * @return []
	*/
	private  R queryByMysql(Class clazz ,String methodName,Object mybatisDao, Map<String,Object> methodParams){
		try {
            //放着注入类
			Method method  = clazz.getDeclaredMethod(methodName,Object.class, Map.class);
            R queryDate = (R) method.invoke(clazz.newInstance() ,mybatisDao, methodParams);
			return  queryDate;
		} catch (NoSuchMethodException e) {
			this.logger.error("the methodName is NoSuchMethodException");
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			this.logger.error("the methodName is InvocationTargetException");
			e.printStackTrace();
		} catch (InstantiationException e) {
            e.printStackTrace();
        }
        return null;
	}
	/**
	 *  需求名称：[需求/BUG名称]
	 *  功能:[按照Keys 从MySQL查询数据]
	 *  创建人:[@wem]
	 *  创建日期:2017年9月20日 下午4:51:51
	 *  功能说明：
	 *	   1.说明1；<br/>
	 *	   2.说明2。<br/>
	 *     ······
	 *  return
	 */
	protected abstract R queryTableByKey(P key);
	/**
	 * 	 
	 *  需求名称：[需求/BUG名称]
	 *  功能:[配置keys]
	 *  创建人:[@user]
	 *  创建日期:2017年9月20日 下午4:00:01
	 *  功能说明：
	 *	   1.说明1；<br/>
	 *	   2.说明2。<br/>
	 *     ······
	 *  @param key 查询key
	 *  @param clazz  查询对象
	 *  @return
	 */
	private String getkeys(P key, Class<R> clazz) {
		 
		return ToolUtils.getClassName(clazz) + "_" + key;
	}
    /**
     *
     *  需求名称：[需求/BUG名称]
     *  功能:[配置一个String的keys]
     *  创建人:[@user]
     *  创建日期:2017年9月20日 下午4:00:01
     *  功能说明：
     *	   1.说明1；<br/>
     *	   2.说明2。<br/>
     *     ······
     *  @param key 查询key
     *  @param clazz  查询对象
     *  return
     */
    private String getStringKeys(Map <String,Object> key, Class<R> clazz) {
        StringBuffer k = new StringBuffer();
        Iterator entries = key.entrySet().iterator();

        while (entries.hasNext()) {
            Map.Entry entry = (Map.Entry) entries.next();
            k.append(entry.getKey());
            k.append(entry.getValue());
        }

        return ToolUtils.getClassName(clazz) + "_" + k.toString();
    }


	 
}
